package com.ark.cloud.dataservices.modules.sys.controller;

import com.alibaba.fastjson.JSONObject;
import com.ark.cloud.dataservices.common.exception.AuthErrorType;
import com.ark.cloud.dataservices.common.utils.IpUtils;
import com.ark.cloud.dataservices.common.web.entity.Result;
import com.ark.cloud.dataservices.config.JwtConfig;
import com.ark.cloud.dataservices.modules.sys.entity.form.LoginForm;
import com.ark.cloud.dataservices.modules.sys.entity.form.ServiceForm;
import com.ark.cloud.dataservices.modules.sys.entity.po.Module;
import com.ark.cloud.dataservices.modules.sys.entity.po.Role;
import com.ark.cloud.dataservices.modules.sys.entity.po.User;
import com.ark.cloud.dataservices.modules.sys.service.IRoleService;
import com.ark.cloud.dataservices.modules.sys.service.ISeatService;
import com.ark.cloud.dataservices.modules.sys.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Copyright(c): 2021 Cloud-Ark Inc.
 * Author(s): Ma Wei (mawei@cloud-ark.com)
 */
@Slf4j
@RestController
@RequestMapping("/auth")
public class LoginController {

    private final JwtConfig jwtConfig;
    private final IUserService userService;
    private final IRoleService roleService;
    private final ISeatService seatService;
    private final PasswordEncoder passwordEncoder;

    public LoginController(IUserService userService, IRoleService roleService, JwtConfig jwtConfig, ISeatService seatService, PasswordEncoder passwordEncoder) {
        this.userService = userService;
        this.roleService = roleService;
        this.jwtConfig = jwtConfig;
        this.seatService = seatService;
        this.passwordEncoder = passwordEncoder;
    }

    @Value("${jwt.header}")
    private String tokenHeader;

    /**
     * 用户登录接口
     *
     * @param loginForm {@link LoginForm}
     * @return {@link Result}
     */
    @PostMapping("/login")
    public Result<?> login(@RequestBody LoginForm loginForm, HttpServletRequest request) {
        JSONObject json = new JSONObject();
        String requestIp = IpUtils.getIpAddr(request);
        User user = userService.getByUniqueId(loginForm.getUsername());
        if (Objects.isNull(user)) {
            return Result.fail(AuthErrorType.UNAUTHORIZED);
        }
        // 验证用户席位是否匹配
        Set<String> seatIps = userService.getSeatIpsByUsername(user.getUsername());
        if(!seatIps.contains("0.0.0.0") && !seatIps.contains(requestIp)) {
            log.warn("登录 IP: {}, 用户席位集合：{}", requestIp, seatIps);
            return Result.fail(50000, "用户席位不匹配");
        }
        // 验证 userName，passWord 和数据库中是否一致
        if (!passwordEncoder.matches(loginForm.getPassword(), user.getPassword())) {
            return Result.fail(AuthErrorType.INVALID_GRANT);
        }
        if (Objects.equals(user.getEnabled(), false)) {
            return Result.fail(AuthErrorType.ACCOUNT_DISABLEED);
        }
        UserDetails userDetails = userService.loadUserByUsername(user.getUsername());
        String token = jwtConfig.generateToken(userDetails);
        if (!StringUtils.isEmpty(token)) {
            json.put("token", token);
            json.put("expire_at", jwtConfig.getExpiredDateFromToken(token).getTime());
        }
        return Result.success(json);
    }

    /**
     * 用户信息
     *
     * @param request {@link HttpServletRequest}
     * @return {@link Result}
     */
    @GetMapping("/info")
    public Result<?> info(HttpServletRequest request) {
        String token = request.getHeader(tokenHeader);
        JSONObject json = new JSONObject();
        String username = null;
        try {
            username = jwtConfig.getUserNameFromToken(token);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (username == null) {
            return Result.fail();
        }

        User user = userService.getByUniqueId(username);
        if (user == null) {
            return Result.fail(50000, "未找到该用户");
        }

        json.put("name", user.getName());
        json.put("avatar", "/static/img/avatar.jpg");
        List<Role> roles = roleService.query(user.getId());
        json.put("roles", roles.stream().map(Role::getCode).collect(Collectors.toSet()));
        return Result.success(json);
    }

    @PostMapping("/logout")
    public Result<?> logout() {
        return Result.success();
    }

    @PutMapping("/changepwd")
    public Result<?> changePwd(HttpServletRequest request, @RequestBody JSONObject form) {
        String newPwd = form.getString("newPwd");
        String oldPwd = form.getString("oldPwd");
        if (newPwd.isEmpty() || oldPwd.isEmpty()) {
            return Result.fail(50000, "密码不能为空！");
        }
        String token = request.getHeader(tokenHeader);
        if (token != null) {
            String username = jwtConfig.getUserNameFromToken(token);
            User user = userService.getByUniqueId(username);
            // 数据库中不存在该用户
            if (Objects.isNull(user)) {
                return Result.fail(AuthErrorType.UNAUTHORIZED);
            }
            // 密码错误
            if (!passwordEncoder.matches(oldPwd, user.getPassword())) {
                return Result.fail(AuthErrorType.INVALID_GRANT);
            }
            // 密码加密
            user.setPassword(passwordEncoder.encode(newPwd));
            return Result.success(userService.update(user));
        } else {
            return Result.fail();
        }
    }

    @PostMapping()
    public Result<?> authToken(@RequestBody ServiceForm serviceForm, HttpServletRequest request) {
        // 获取请求头
        String license = request.getHeader(this.tokenHeader);
        if (StringUtils.isBlank(license)) {
            return Result.fail(50000, "请求头中未包含 License");
        }
        // 根据 License 获取服务 ip
        String seatIp = seatService.getIpAddrByLicense(license);
        if (!seatIp.equals("0.0.0.0") && !seatIp.equals(serviceForm.getIp())) {
            log.warn("IP: {}\tServiceName: {}\tSeatIP: {}", serviceForm.getIp(), serviceForm.getServiceName(), seatIp);
            return Result.fail(50000, "License 与服务相关信息不匹配");
        }
        return Result.success("验证成功");
    }

    @GetMapping("/modules")
    public Result<?> getModules(HttpServletRequest request) {
        String token = request.getHeader(tokenHeader);
        if (token != null) {
            String username = jwtConfig.getUserNameFromToken(token);

            Set<Module> modules = userService.getModulesByUsername(username);
            return Result.success(modules.parallelStream().collect(Collectors.groupingBy(Module::getType)));
        } else {
            return Result.fail(50000, "用户未登录");
        }
    }

}
